package com.tidc.seaserverweb.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.tidc.seaservermodel.entity.Fres;
import com.tidc.seaservermodel.util.RedisUtil;
import com.tidc.seaserverservice.service.impl.MyUserAuthorizationServiceImpl;
import com.tidc.seaserverweb.filter.AuthenticationTokenFilter;
import com.tidc.seaserverweb.filter.LoginFilter;
import com.tidc.seaserverweb.handler.MyAccessDeniedHandler;
import com.tidc.seaserverweb.handler.NotLoginHandler;
import com.tidc.seaserverweb.handler.TidcAuthenticationSuccessHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.*;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;
import java.io.*;


@Order(-1)
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Slf4j
public class MySecurityConfig  extends WebSecurityConfigurerAdapter {

    @Resource
    private AuthenticationTokenFilter authenticationTokenFilter;

    @Resource
    private NotLoginHandler notLoginHandler;
    @Resource
    private MyUserAuthorizationServiceImpl myUserAuthorizationService;

    @Resource
    private MyAccessDeniedHandler myAccessDeniedHandler;

    @Resource
    private TidcAuthenticationSuccessHandler tidcAuthenticationSuccessHandler;
    @Resource
    private RedisUtil redisUtil;

    /**
     * 注册密码加密组件
     *
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 提供给来作用认证
     *
     * @return
     * @throws Exception
     */
    @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {


            return super.authenticationManagerBean();


    }

    /**
     * 使用自定义的 userDetailService来做用户认证
     *
     * @param auth
     * @throws Exception
     */
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserAuthorizationService)
                .passwordEncoder(passwordEncoder());
    }

    @Bean
    LoginFilter loginFilter() throws Exception {
        LoginFilter loginFilter = new LoginFilter();
        loginFilter.setAuthenticationSuccessHandler(tidcAuthenticationSuccessHandler);
        loginFilter.setAuthenticationFailureHandler((request, response, exception) -> {
                    response.setContentType("application/json;charset=utf-8");
                    PrintWriter out = response.getWriter();
                    Fres<String> fres = null;
                    String message = null;
                    if (exception instanceof LockedException) {
                        message = "账户被锁定，请联系管理员!";
                    } else if (exception instanceof CredentialsExpiredException) {
                       message = "密码过期，请联系管理员!";
                    } else if (exception instanceof AccountExpiredException) {
                        message = "账户过期，请联系管理员!";
                    } else if (exception instanceof DisabledException) {
                        message = "账户被禁用，请联系管理员!";
                    } else if (exception instanceof BadCredentialsException) {
                        message = "用户名或者密码输入错误，请重新输入!";
                    }else if (exception instanceof InternalAuthenticationServiceException) {
                        message = "用户名或者密码输入错误，请重新输入!";
                    }
                    fres = Fres.badRequestParent("", message);
                    out.write(new ObjectMapper().writeValueAsString(fres));
                    out.flush();
                    out.close();
                }
        );
        //加入认证过滤器链
        loginFilter.setAuthenticationManager(authenticationManagerBean());
//        设置过滤的网站
        loginFilter.setFilterProcessesUrl("/login");
//        这个是设置session的无所谓
        return loginFilter;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterAt(loginFilter(), UsernamePasswordAuthenticationFilter.class);
        http
                // 使用自定义授权过滤器
                .addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
                // 授权请求
                .authorizeRequests()
                .antMatchers("/secondary/**").hasAnyRole("secondary", "supervisor")
                .antMatchers("/supervisor/**").hasAnyRole("supervisor")
                .antMatchers("/rabbit/**").hasAnyRole("admin")
                .antMatchers("/quartz/**").hasAnyRole("admin")
                // 放行url
                .antMatchers(
                        "/user/**",
                        "/hello",
                        "/ilogin",
                        "/menus"
                ).permitAll()
                .and()
                .exceptionHandling()
                // 未登录响应处理
                .authenticationEntryPoint(notLoginHandler)
                // 无权限访问响应处理
                .accessDeniedHandler(myAccessDeniedHandler);

        //禁用缓存
        http.headers().cacheControl();
        //禁用session
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        http.csrf().disable();
        http.cors();

    }

    //
    @Override
    public void configure(WebSecurity web) {
        //将项目中静态资源路径开放出来
        web.ignoring().antMatchers("/css/**", "/fonts/**", "/img/**", "/js/**", "/webjars/**");


    }


}
